﻿#include "tcpclienttunnel.h"
#include "tunnelcallback.h"

#include <net/tcpclient.h>
#include <net/netwriting.h>

#include <QThread>

QNET_USING_NAMESPACE;
TcpClientTunnel::TcpClientTunnel(const IPFiveTuple &ipTuple)
    : m_ipTuple(ipTuple)
{
    m_client = Q_NULLPTR;
    m_session = Q_NULLPTR;
    m_state = false;
    m_innerThread = Q_NULLPTR;

    static int id = qRegisterMetaType<QSharedPointer<NetWriting>>("QSharedPointer<NetWriting>");
    Q_UNUSED(id)
}

TcpClientTunnel::~TcpClientTunnel()
{

}

bool TcpClientTunnel::build()
{
    if(m_client)
    {
        m_client->deleteLater();
    }
    m_client = new TcpClient(this);
   if(!m_client->bind(m_ipTuple.localAddr(), m_ipTuple.localPort()))
   {
       m_client->deleteLater();
       m_client = Q_NULLPTR;
       return false;
   }

   if(m_innerThread)
   {
       m_innerThread->deleteLater();
   }
   m_innerThread = new QThread;
   QObject::connect(m_innerThread, &QThread::finished, m_innerThread, &QThread::deleteLater);
   QObject::connect(m_innerThread, &QThread::finished, m_client, &TcpClient::deleteLater);

   m_innerThread->start();
   m_client->setAutoReconnect(false); // 不自动重连。
   m_client->connect(m_ipTuple.remoteAddr(), m_ipTuple.remotePort());
   m_client->moveToThread(m_innerThread);
   return true;
}

void TcpClientTunnel::destory()
{
    if(m_client)
    {
        m_client->setListener(Q_NULLPTR);
    }
    if(m_innerThread){
        m_innerThread->exit();
    }
}

int TcpClientTunnel::write(QByteArray &src)
{
    if(m_state && m_session)
    {
        NetWriting *pWriting = new NetWriting;
        pWriting->setData(src);
        QSharedPointer<NetWriting> writing(pWriting, &NetWriting::deleteLater);
        return m_session->write(writing);
    }
    return false;
}

bool TcpClientTunnel::state()
{
    return m_state;
}

void TcpClientTunnel::disConnect()
{
    if(m_state && m_session)
    {
        m_session->setReading(Q_NULLPTR);
        m_session->close();
    }
}

void TcpClientTunnel::fetchTuple(IPFiveTuple &tuple)
{
    tuple.setType(IPFiveTuple::Type_TcpClient);
    if(m_session)
    {
        tuple.setLocalPort(m_session->localPort());
        tuple.setLocalAddr(m_session->localIp());
        tuple.setRemotePort(m_session->remotePort());
        tuple.setRemoteAddr(m_session->remoteIp());
    }
}

void TcpClientTunnel::onStateChanged(TcpSession *session, bool connected)
{
    m_state = connected;
    if(connected)
    {
        m_session = session;
        m_session->setReading(this);
    }else
    {
        if(session && m_session == session)
        {
            m_session->setReading(Q_NULLPTR);
        }
    }
    auto func = [=](TunnelCallback *item)->void {item->onStateChange(connected);};
    execEach(func);
}

void TcpClientTunnel::onError(QAbstractSocket::SocketError error)
{
    if(error == QAbstractSocket::ConnectionRefusedError)
    {
        onStateChanged(Q_NULLPTR, false);
    }
}

void TcpClientTunnel::onProc(const QByteArray &arry)
{
    auto func = [=](TunnelCallback *item)->void {item->onProc(arry);};
    execEach(func);
}
